/*
 * Copyright 2008 Zoundry LLC, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.zoundry.gaedt.core.models;

import java.lang.reflect.Method;
import javax.xml.namespace.QName;
import org.apache.commons.lang.WordUtils;

/**
 * A base implementation of the attribute type mapper.  This implementation will
 * try to figure out which Java primitive type to convert to based on the Bean/POJO
 * setter return type.
 */
public class ZGaeModelTypeMapper implements IZGaeModelTypeMapper
{
    /**
     * @see org.zoundry.gaedt.core.models.IZGaeModelTypeMapper#convertAttributeValue(java.lang.String, org.zoundry.gaedt.core.models.ZGaeModel, javax.xml.namespace.QName)
     */
    public Object convertAttributeValue(String aValueStr, ZGaeModel aModel, QName aName)
    {
        String ns = aName.getNamespaceURI();
        if (ns != null && !"".equals(ns))
            throw new RuntimeException("Could not convert attribute (qualified attributes not supported): " + aName);

        Class type = getAttributeType(aModel, aName);

        if (type == null)
            return null;
        Object rValue = convertToType(aValueStr, type);
        return rValue;
    }

    /**
     * Gets the type of the given attribute for the given model.
     *
     * @param aModel
     * @param aName
     */
    protected Class getAttributeType(ZGaeModel aModel, QName aName)
    {
        Class type = null;
        String setterMethodName = "set" + WordUtils.capitalize(aName.getLocalPart());
        Method[] methods = aModel.getClass().getMethods();
        for (Method method : methods)
        {
            if (method.getName().equals(setterMethodName))
            {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1)
                {
                    type = parameterTypes[0];
                    break;
                }
            }
        }
        return type;
    }

    /**
     * Converts the given string to the given type.
     *
     * @param aValueStr
     * @param aType
     */
    private Object convertToType(String aValueStr, Class aType)
    {
        // TODO improve how type conversion happens - factory/map is needed
        if (aType.equals(Integer.class) || aType.equals(int.class))
            return Integer.parseInt(aValueStr);
        else if (aType.equals(Long.class) || aType.equals(long.class))
            return Long.parseLong(aValueStr);
        else if (aType.equals(Boolean.class) || aType.equals(boolean.class))
            return Boolean.parseBoolean(aValueStr);
        else if (aType.equals(String.class))
            return aValueStr;
        return null;
    }

    /**
     * @see org.zoundry.gaedt.core.models.IZGaeModelTypeMapper#convertElementValue(org.zoundry.gaedt.core.models.ZGaeModel, java.lang.String)
     */
    public Object convertElementValue(ZGaeModel aModel, String aModelValueStr)
    {
        Class type = null;
        Method[] methods = aModel.getClass().getMethods();
        for (Method method : methods)
        {
            if (method.getName().equals("setValue"))
            {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1)
                {
                    type = parameterTypes[0];
                    break;
                }
            }
        }
        if (type == null)
            return null;
        Object rValue = convertToType(aModelValueStr, type);
        return rValue;
    }
}
